﻿using System;
using System.Collections.Generic;
using System.Linq;
using SIG.Model;
using SIG.Repository;
using SIG.Infrastructure.Logging;
using SIG.Infrastructure.Cache;
using SIG.Infrastructure.Configs;
using SIG.Resources.Admin;
using System.Linq.Expressions;
using SIG.Basic.Extensions;

namespace SIG.Service
{
    public class ProductService: EntityService<Product>, IProductService
    {
       
        private readonly IProductRepository _productRepository;
        private readonly ICategoryRepository _categoryRepository;
        private readonly ILoggingService _loggingService;
        private readonly ICacheService _cacheService;

        public ProductService(IProductRepository productRepository, ICategoryRepository categoryRepository,ILoggingService loggingService, 
            ICacheService cacheService)
            : base( productRepository, cacheService, loggingService)
        {
           
            _productRepository = productRepository;
            _categoryRepository = categoryRepository;
            _loggingService = loggingService;
            _cacheService = cacheService;
        }


       

        public Product GetProductByIdWithCategories(int id)
        {
          
            var key = $"{EntityNames.Product}_Categories_{id}";

            if (!SettingsManager.Product.EnableCaching)
            {
                return _productRepository.GetFirstOrDefault((p=>p.Id == id),(p=>p.Categories));
            }           

            if (_cacheService.IsSet(key))            
                return (Product)_cacheService.Get(key);
          

            Product product = _productRepository.GetFirstOrDefault((p => p.Id == id), (p => p.Categories));
            _cacheService.Set(key, product, SettingsManager.Product.CacheDuration);
           
            return product;
        }



        public List<Product> GetActivePagedElements(int pageIndex, int pageSize, string keyword, int? categoryId, out int totalCount)
        {

            //get list count
            var keyCount = $"{EntityNames.Product}_Active_ListCount_{keyword}_{categoryId}";

            var totalIQuery = _productRepository.GetAllElements().Where(m=>m.Active);
            if (!string.IsNullOrEmpty(keyword))
                totalIQuery = totalIQuery.Where(g => g.ProductName.Contains(keyword));
            if (categoryId > 0)
                totalIQuery = totalIQuery.Where(g => g.Categories.Contains(g.Categories.FirstOrDefault(m => m.Id == (int)categoryId)));

            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(keyCount))
                {
                    totalCount = (int)_cacheService.Get(keyCount);
                }
                else
                {
                    totalCount = totalIQuery.Count();
                    _cacheService.Set(keyCount, totalCount, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                totalCount = totalIQuery.Count();
            }


            //get list
            var key = $"{EntityNames.Product}_Active_List_{pageIndex}_{pageSize}_{keyword}_{categoryId}";

            List<Product> products;
            Expression<Func<Product, bool>> filter = g => g.Active;
            Expression<Func<Product, bool>> filterByKeyword = g => g.ProductName.Contains(keyword);
            Expression<Func<Product, bool>> filterByCategory = g => g.Categories.Contains(g.Categories.FirstOrDefault(m => m.Id == (int)categoryId));

            if (!string.IsNullOrEmpty(keyword))
                filter = filter.AndAlso(filterByKeyword);
            if (categoryId > 0)
                filter = filter.AndAlso(filterByCategory);


            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    products = (List<Product>)_cacheService.Get(key);
                }
                else
                {
                    products = _productRepository.GetPagedElements(pageIndex, pageSize, (c => c.CreatedDate), filter, false, g => g.Categories, g => g.ProductPhotoes).ToList();
                    _cacheService.Set(key, products, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                products = _productRepository.GetPagedElements(pageIndex, pageSize, (c => c.CreatedDate), filter, false, g => g.Categories, g => g.ProductPhotoes).ToList();
            }

            return products;

        }

        public List<Product> GetPagedElements(int pageIndex, int pageSize, string keyword, int? categoryId, out int totalCount)
        {

            //get list count
            var keyCount = $"{EntityNames.Product}_ListCount_{keyword}_{categoryId}";

            var totalIQuery = _productRepository.GetAllElements();
            if (!string.IsNullOrEmpty(keyword))
                totalIQuery = totalIQuery.Where(g => g.ProductName.Contains(keyword));
            if (categoryId > 0)
                totalIQuery = totalIQuery.Where(g => g.Categories.Contains(g.Categories.FirstOrDefault(m=>m.Id == (int)categoryId)));

            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(keyCount))
                {
                    totalCount = (int)_cacheService.Get(keyCount);
                }
                else
                {
                    totalCount = totalIQuery.Count();
                    _cacheService.Set(keyCount, totalCount, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                totalCount = totalIQuery.Count();
            }


            //get list
            var key = $"{EntityNames.Product}_List_{pageIndex}_{pageSize}_{keyword}_{categoryId}";

            List<Product> products;
            Expression<Func<Product, bool>> filter = g => true;
            Expression<Func<Product, bool>> filterByKeyword = g => g.ProductName.Contains(keyword);
            Expression<Func<Product, bool>> filterByCategory = g => g.Categories.Contains(g.Categories.FirstOrDefault(m => m.Id == (int)categoryId));

            if (!string.IsNullOrEmpty(keyword))
                filter = filter.AndAlso(filterByKeyword);
            if (categoryId > 0)
                filter = filter.AndAlso(filterByCategory);


            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    products = (List<Product>)_cacheService.Get(key);

                }
                else
                {
                    products =  _productRepository.GetPagedElements(pageIndex, pageSize, (c => c.CreatedDate), filter, false, g => g.Categories,g=>g.ProductPhotoes).ToList();
                    _cacheService.Set(key, products, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                products = _productRepository.GetPagedElements(pageIndex, pageSize, (c => c.CreatedDate), filter, false, g => g.Categories, g => g.ProductPhotoes).ToList();
            }

            return products;

        }

        public List<Product> RecommendProducts(int count)
        {

            var key = $"{EntityNames.Product}_RECOMMEND_PRODUCTS_{count}";

            if (!SettingsManager.Product.EnableCaching)
            {
                return GetProducts(count);
            }

            if (_cacheService.IsSet(key))
                return (List<Product>)_cacheService.Get(key);


            List<Product> products = GetProducts(count);
            _cacheService.Set(key, products, SettingsManager.Product.CacheDuration);

            return products;
        }

        private List<Product> GetProducts(int count)
        {
            return _productRepository.GetAllElements().Where(m => m.Recommend).OrderByDescending(m => m.CreatedDate).Take(count).ToList();
        }

        public void UpdateProductWithCategory(Product product)
        {
          
            var p = _productRepository.GetFirstOrDefault((prod=> prod.Id == product.Id), (prod => prod.Categories));

            p.ProductNo = product.ProductNo;
            p.ProductName = product.ProductName;
            p.Body = product.Body;
            p.Description = product.Description;
            p.Thumbnail = product.Thumbnail;
          //  p.Keywords = product.Keywords;
            p.Recommend = product.Recommend;
            p.Active = product.Active;
        
            p.PostCategoryIds = product.PostCategoryIds;      
            
            var lCategories = (from c in _categoryRepository.GetAllElements()
                                 where product.PostCategoryIds.Contains(c.Id.ToString())
                                   select c).ToList();

            p.Categories.Clear();
            p.Categories = lCategories;
           
            //foreach (var c in lCategories)
            //{
            //    p.Categories.Add(c);
            //}
            Update(p);
            //_unitOfWork.GetRepository<Product>().Update(product);
            //_unitOfWork.SaveChanges();

            //_cacheService.Invalidate("Product");
            //_loggingService.Info(string.Format(Site.logCreateMessage,Site.Settings.Product.SetName, product.ProductNo, Site.CurrentUserName));
        }

 
    }
}
